(module table-interface mzscheme

  (require "../private/require.ss")
  (require-class)
  (require-contracts)

  (provide table<%> table?
           table/c non-empty-table/c
           table-of/c non-empty-table-of/c)

  (define table<%>
    (interface ()

      ;; (send (Table Key Value) sexp) : (List (list Key Value))
      ;; Converts a table to an s-expression containing each key/value
      ;; binding as a two-element list.
      sexp

      ;; (send (Table Key Value) alist) : (List (cons Key Value))
      ;; Converts a table into an association list containing each
      ;; key/value binding as a pair.  The order of the pairs corresponds
      ;; to their order from sexp (above).
      alist

      ;; (send (Table Key Value) keys) : (List Key)
      ;; Produces the list of keys in the table.  The order corresponds
      ;; to alist and sexp (above).
      keys

      ;; (send (Table Key Value) values) : (List Value)
      ;; Produces the list of values in the table.  The order corresponds
      ;; to alist, sexp, and keys (above).
      values

      ;; (send (Table Key Value) insert Key Value) : (Table Key Value)
      ;; Inserts a binding of a given key to a given value into the table.
      insert

      ;; (send (Table Key Value) lookup Key [(-> T) (Value -> T)]) : T
      ;; Looks up a key's binding in a table.
      ;; If found, applies the success function to the corresponding value
      ;; (defaults to return the value).
      ;; If not found, applies the failure thunk (defaults to return #f).
      lookup

      ;; (send (Table Key Value) lookup/key Key [(-> T) (Key Value -> T)]) : T
      ;; Looks up a key's binding in a table.
      ;; If found, applies the success function to the corresponding binding
      ;; (defaults to return the key).
      ;; If not found, applies the failure thunk (defaults to return #f).
      lookup/key

      ;; (send (Table Key Value) iterator) : (IndexedIterator Key Value)
      ;; Produces an iterator over a table's bindings.
      iterator

      ;; (send (Table Key Value) remove Key) : (Table Key Value)
      ;; Removes the binding for the given key, if any.
      remove

      ;; (send (Table Key Value) update Key (Key Value -> Value)) :
      ;; (Table Key Value)
      ;; (send (Table Key Value) update/value Key (Value -> Value) :
      ;; (Table Key Value)
      ;; (send (Table Key Value) update/insert Key (Key Value -> Value) Value) :
      ;; (Table Key Value)
      ;; (send (Table Key Value) update/insert/value Key (Value -> Value) Value)
      ;; : (Table Key Value)
      ;; Transforms the binding for the given key to hold a new value.
      ;; The /insert version insert the given value if no binding is found,
      ;; the standard version makes no change if no binding is found.
      update update/value update/insert update/insert/value

      ;; (send (Table Key Value) select) : (values Key Value)
      ;; (send (Table Key Value) select/key) : Key
      ;; (send (Table Key Value) select/value) : Value
      ;; Selects a single binding (or key or value) from a table.
      ;; It is an error to invoke these methods on an empty table.
      select select/key select/value

      ;; (send (Table Key Value) empty?) : Boolean
      ;; Reports whether the table is empty.
      empty?

      ;; (send (Table Key Value) clear) : (Table Key Value)
      ;; Produces an empty table with the same properties as the receiver.
      clear

      ;; (send (Table Key Value) size) : NaturalNumber
      ;; Produces the number of bindings in the table.
      size

      ;; (send (Table Key Value) contains? Key) : Boolean
      ;; Reports whether the table contains a given key.
      contains?

      ;; (send (Table Key Value) fold (Key Value T -> T) T) : T
      ;; (send (Table Key Value) fold/key (Key T -> T) T) : T
      ;; (send (Table Key Value) fold/value (Value T -> T) T) : T
      ;; Builds a result from each binding/key/value in the table.
      fold fold/key fold/value

      ;; (send (Table Key A) map (Key A -> B)) : (Table Key B)
      ;; (send (Table Key A) map/key (Key -> B)) : (Table Key B)
      ;; (send (Table Key A) map/value (A -> B)) : (Table Key B)
      ;; Replaces a table's value based on the previous binding/key/value.
      map map/key map/value

      ;; (send (Table Key Value) for-each (Key Value -> Void)) : Void
      ;; (send (Table Key Value) for-each/key (Key -> Void)) : Void
      ;; (send (Table Key Value) for-each/value (Value -> Void)) : Void
      ;; Performs an action for each binding/key/value in the table.
      for-each for-each/key for-each/value

      ;; (send (Table K V) filter (K V -> Boolean)) : (Table K V)
      ;; (send (Table K V) filter/key (K -> Boolean)) : (Table K V)
      ;; (send (Table K V) filter/value (V -> Boolean)) : (Table K V)
      ;; Retains those bindings which satisfy the predicate.
      filter filter/key filter/value

      ;; (send (Table Key Value) all? (Key Value -> Boolean)) : Boolean
      ;; (send (Table Key Value) all?/key (Key -> Boolean)) : Boolean
      ;; (send (Table Key Value) all?/value (Value -> Boolean)) : Boolean
      ;; Reports whether all bindings/keys/values satisfy the predicate.
      all? all?/key all?/value

      ;; (send (Table Key Value) any? (Key Value -> Boolean)) : Boolean
      ;; (send (Table Key Value) any?/key (Key -> Boolean)) : Boolean
      ;; (send (Table Key Value) any?/value (Value -> Boolean)) : Boolean
      ;; Reports whether any bindings/keys/values satisfy the predicate.
      any? any?/key any?/value

      ;; (send (Table Key Value) union (Table Key Value)
      ;;       [(Key Value Value -> Value)]) : (Table Key Value)
      ;; (send (Table Key Value) union/value (Table Key Value)
      ;;       [(Value Value -> Value)]) : (Table Key Value)
      ;; Creates a table containing all keys from either, using the optional
      ;; argument to combine bindings for duplicate keys (defaults to choosing
      ;; one binding or the other).
      union union/value

      ;; (send (Table Key Value) intersection (Table Key Value)
      ;;       [(Key Value Value -> Value)]) : (Table Key Value)
      ;; (send (Table Key Value) intersection/value (Table Key Value)
      ;;       [(Value Value -> Value)]) : (Table Key Value)
      ;; Creates a table containing keys present in both, using the optional
      ;; argument to combine bindings for duplicate keys (defaults to choosing
      ;; one binding or the other).
      intersection intersection/value

      ;; (send (Table Key Value) difference (Table Key Value)) : (Table Key Value)
      ;; Creates a table containing all bindings in the receiver that are
      ;; not present in the argument.
      difference

      ;; (send (Table Key Value) subtable? (Any Any -> Boolean) (Table Key Value))
      ;; : Boolean
      ;; Reports whether all bindings in the receiver are contained in the
      ;; table argument, using the predicate to compare bound values.
      subtable?

      ;; (send (Table Key Value) equal? (Any Any -> Boolean) (Table Key Value))
      ;; : Boolean
      ;; Reports whether both tables contain the same bindings, using the predicate
      ;; to compare bound values.
      equal?

      ))

  (define table/c (is-a?/c table<%>))
  (define non-empty/c (not/c (lambda (table) (send table empty?))))

  (define non-empty-table/c
    (and/c table/c non-empty/c))

  (define (table-of/c key/c value/c)
    (and/c table/c
           (lambda (table)
             (and (send table all?/key (predicate-of key/c))
                  (send table all?/value (predicate-of value/c))))))

  (define (non-empty-table-of/c key/c value/c)
    (and/c (table-of/c key/c value/c) non-empty/c))

  ;; table? : Any -> Boolean
  ;; Reports whether a value is a table.
  (define (table? v)
    (is-a? v table<%>))

  )